"""
OpenRouter API提供商
支持通过OpenRouter访问各种模型，包括Claude 3.7 Thinking
"""
import json
import os
import time
import logging
from typing import Dict, List, Optional, Any, Generator
import requests

from ..core.provider import RemoteProvider
from ..core.exceptions import map_provider_error
from ..implementations.openrouter.streaming import OpenRouterStreaming
from ..implementations.openrouter.thinking import OpenRouterThinking
from ..core.provider_registry import register_provider

# 设置日志
logger = logging.getLogger("llm.openrouter")


@register_provider("openrouter")
class OpenRouterProvider(RemoteProvider):
    """OpenRouter API提供商"""
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化OpenRouter提供商
        
        Args:
            config: 配置字典
        """
        # 处理应用程序信息
        self.app_name = config.get("app_name", "Py-Cline")
        self.app_url = config.get("app_url", "https://py-cline.local")
        
        # 确保正确初始化所有父类
        super().__init__(config)
        
        # 初始化特有配置
        self.model = config.get("model", "anthropic/claude-3.7-sonnet:thinking")
        
        # 验证配置
        self._validate_config(config)
            
    def _validate_config(self, config: Dict[str, Any]) -> None:
        """
        验证配置合法性
        
        Args:
            config: 配置字典
            
        Raises:
            ConfigurationError: 如果配置不合法
        """
        # API密钥验证已在RemoteProvider中完成
        
        # 验证模型名称
        # OpenRouter支持多种格式的模型名称，因此不做严格验证
        pass
            
    def _init_capabilities(self) -> None:
        """初始化OpenRouter支持的功能组件"""
        logger.debug("初始化OpenRouter功能组件")

        # 添加流式输出功能
        self.register_capability("streaming", OpenRouterStreaming)

        # 添加思考过程功能
        self.register_capability("thinking", OpenRouterThinking)
        
    def complete(self, messages: List[Dict[str, str]], stream: bool = False) -> str:
        """
        获取LLM完成
        
        Args:
            messages: 消息列表
            stream: 是否使用流式响应
            
        Returns:
            完成的文本
        """
        if stream:
            return "".join([chunk for chunk in self.complete_stream(messages)])
            
        response = self._call_with_retry(self._complete_internal, messages)
        
        # 提取响应文本
        if not isinstance(response, (str, dict)):
            raise Exception(f"无效的API响应: {type(response)}")
            
        # 处理字符串结果
        if isinstance(response, str):
            return response
            
        # 提取思考过程（如果有）
        thinking = self.extract_thinking(response)
        if thinking:
            logger.debug(f"思考过程: {thinking}")
            
        return response
    
    def _complete_internal(self, messages: List[Dict[str, Any]]) -> str:
        """
        内部完成实现
        
        Args:
            messages: 消息列表
            
        Returns:
            完成的文本
        """
        start_time = time.time()
        
        try:
            # 准备请求头
            headers = {
                "Authorization": f"Bearer {self.api_key}",
                "HTTP-Referer": self.app_url,
                "X-Title": self.app_name,
                "Content-Type": "application/json"
            }
            
            # 准备请求数据
            data = {
                "model": self.model,
                "messages": messages,
                "max_tokens": self.max_tokens,
                "temperature": self.temperature
            }
            
            # 过滤参数
            _, kwargs = self.filter_chat_args(model=self.model, messages=messages, 
                                             max_tokens=self.max_tokens, 
                                             temperature=self.temperature)
            data.update(kwargs)
            
            # 发送请求
            response = requests.post(
                "https://openrouter.ai/api/v1/chat/completions",
                headers=headers,
                json=data
            )
            
            if response.status_code != 200:
                raise Exception(f"API请求失败: {response.status_code} {response.text}")
                
            result_json = response.json()
            result = result_json["choices"][0]["message"]["content"]
            
            # 计算token使用量
            input_tokens, output_tokens = self.calculate_tokens(result_json)
            cost = self.calculate_cost(input_tokens, output_tokens)
            
            elapsed = time.time() - start_time
            logger.info(f"OpenRouter请求完成，耗时: {elapsed:.2f}秒，模型: {self.model}, "
                       f"输入: {input_tokens}tokens, 输出: {output_tokens}tokens, "
                       f"成本: ${cost:.6f}")
            
            return result
        except Exception as e:
            elapsed = time.time() - start_time
            logger.error(f"OpenRouter请求失败，耗时: {elapsed:.2f}秒，错误: {str(e)}")
            
            # 映射错误为标准LLM异常
            mapped_error = map_provider_error("openrouter", e, self.model)
            raise mapped_error
            
    def complete_stream(self, messages: List[Dict[str, str]]) -> Generator[str, None, None]:
        """
        获取LLM流式完成
        
        Args:
            messages: 消息列表
            
        Returns:
            流式响应生成器
        """
        # 检查是否支持流式输出
        if not self.has_capability("streaming"):
            # 如果不支持流式输出，使用标准完成方法并逐字符生成
            content = self._complete_internal(messages)
            for char in content:
                yield char
            return
            
        # 使用流式输出能力组件
        streaming = self.get_capability("streaming")
        yield from streaming.stream_response(messages)
            
    def extract_thinking(self, response: Dict[str, Any]) -> Optional[str]:
        """
        从响应中提取思考过程
        
        Args:
            response: API响应数据
            
        Returns:
            思考过程字符串，如果不存在则返回None
        """
        # 检查是否支持思考过程提取
        if not self.has_capability("thinking"):
            return None
            
        # 使用思考过程能力组件
        thinking = self.get_capability("thinking")
        return thinking.extract_thinking(response)
        
    def calculate_tokens(self, response: Dict[str, Any]) -> tuple[int, int]:
        """
        计算输入和输出令牌数
        
        Args:
            response: 响应数据
            
        Returns:
            (输入令牌数, 输出令牌数)元组
        """
        # 从OpenRouter响应中提取token使用量
        if "usage" in response:
            usage = response["usage"]
            return usage.get("prompt_tokens", 0), usage.get("completion_tokens", 0)
            
        # 如果没有usage信息，使用基类的估算方法
        return super().calculate_tokens(response)
        
    def filter_chat_args(self, **kwargs) -> tuple:
        """
        过滤和处理API调用参数
        
        Args:
            **kwargs: 关键字参数
            
        Returns:
            处理后的(args, kwargs)元组
        """
        # 某些模型可能不支持temperature参数
        if "o1" in self.model and "temperature" in kwargs:
            kwargs.pop("temperature")
            
        return (), kwargs
